<!DOCTYPE html>
<html lang="zh-CN">

<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>Gerrit链接解析工具分析报告-{{changeID}}</title>
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css" />
  <script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.8/dist/chart.umd.min.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/xlsx@0.18.5/dist/xlsx.full.min.js"></script>
  <style>
    :root {
      --primary-color: #2563eb;
      /* 更鲜明的主色调 */
      --primary-light: #3b82f6;
      --secondary-color: #64748b;
      --accent-color: #10b981;
      --danger-color: #ef4444;
      --warning-color: #f59e0b;
      --light-gray: #f8fafc;
      --mid-gray: #e2e8f0;
      --dark-gray: #334155;
      --border-radius: 8px;
      --shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
      --shadow-hover: 0 6px 16px rgba(0, 0, 0, 0.12);
      --transition: all 0.3s ease;
      --transition-fast: all 0.2s ease;
    }

    * {
      margin: 0;
      padding: 0;
      box-sizing: border-box;
    }

    body {
      font-family: "Inter", "Segoe UI", Tahoma, Geneva, Verdana, sans-serif;
      line-height: 1.6;
      color: var(--dark-gray);
      background-color: #f1f5f9;
      padding: 20px 15px;
    }

    .container {
      max-width: 100%;
      /* 增加最大宽度 */
      margin: 0 auto;
      background-color: white;
      padding: 30px;
      border-radius: var(--border-radius);
      box-shadow: var(--shadow);
    }

    header {
      text-align: center;
      margin-bottom: 30px;
      padding-bottom: 20px;
      border-bottom: 1px solid var(--mid-gray);
    }

    .header-content {
      display: flex;
      align-items: center;
      justify-content: center;
      gap: 12px;
      margin-bottom: 8px;
    }

    .header-icon {
      color: var(--primary-color);
      font-size: 1.5rem;
    }

    h1 {
      color: var(--primary-color);
      font-weight: 600;
      margin: 0;
    }

    .subtitle {
      color: var(--secondary-color);
      font-weight: 400;
      font-size: 1.1rem;
    }

    .input-section {
      margin-bottom: 30px;
    }

    .input-group {
      display: flex;
      gap: 12px;
    }

    .input-wrapper {
      position: relative;
      flex: 1;
    }

    #urlInput {
      width: 100%;
      padding: 12px 15px;
      padding-right: 40px;
      border: 1px solid var(--mid-gray);
      border-radius: var(--border-radius);
      font-size: 16px;
      transition: var(--transition);
    }

    #urlInput:focus {
      outline: none;
      border-color: var(--primary-color);
      box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.1);
    }

    /* 实时验证提示 */
    .validation-hint {
      margin-top: 6px;
      font-size: 0.85rem;
      height: 1.2rem;
      color: var(--danger-color);
    }

    .clear-btn {
      position: absolute;
      right: 8px;
      top: 50%;
      transform: translateY(-50%);
      background: none;
      border: none;
      color: var(--secondary-color);
      cursor: pointer;
      width: 24px;
      height: 24px;
      border-radius: 50%;
      display: flex;
      align-items: center;
      justify-content: center;
      opacity: 0;
      visibility: hidden;
      transition: var(--transition);
    }

    .clear-btn.visible {
      opacity: 1;
      visibility: visible;
    }

    .clear-btn:hover {
      background-color: var(--light-gray);
      color: var(--danger-color);
    }

    .btn-primary {
      padding: 12px 24px;
      background-color: var(--primary-color);
      color: white;
      border: none;
      border-radius: var(--border-radius);
      cursor: pointer;
      font-size: 16px;
      font-weight: 500;
      transition: var(--transition);
      white-space: nowrap;
      margin-left: auto;
      /* display: inline-flex;
    align-items: center;
    gap: 8px; */
    }

    .btn-primary:hover {
      background-color: var(--primary-light);
      transform: translateY(-2px);
      box-shadow: 0 4px 8px rgba(37, 99, 235, 0.2);
    }

    .btn-primary:active {
      transform: translateY(0);
    }

    .btn-primary:disabled {
      background-color: var(--mid-gray);
      cursor: not-allowed;
      transform: none;
      box-shadow: none;
    }

    /* 加载动画 */
    .loading-spinner {
      font-size: 1.2rem;
    }

    .result-section {
      margin-top: 20px;
      display: flex;
      flex-direction: column;
      gap: 20px;
      /* 卡片间距 */
    }

    .details-card {
      background-color: var(--light-gray);
      border-radius: var(--border-radius);
      padding: 20px;
      transition: var(--transition);
      border: 1px solid transparent;
    }

    .details-card:hover {
      box-shadow: var(--shadow-hover);
      border-color: var(--mid-gray);
    }

    /* 浮窗样式 */
    #detailTooltip {
      position: fixed;
      /* 相对于视口定位 */
      top: 50px;
      left: 50px;
      border: 1px solid #ccc;
      background: white;
      padding: 16px;
      max-width: 60%;
      /* 限制最大宽度（避免过宽） */
      max-height: 80%;
      /* 限制最大高度（避免过高） */
      overflow: auto;
      /* 内容超出最大尺寸时显示滚动条 */
      box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
      z-index: -1;
      /* 默认隐藏时在最底层 */
    }

    #detailTooltip.show {
      display: block;
      opacity: 1;
      transform: translateY(0);
      z-index: 9999;
      /* 显示时在最上层 */
    }

    #detailTooltip:hover {
      background-color: #d8e1f1;
    }

    .tooltip-content {
      max-height: 500px;
      margin-bottom: 8px;
    }

    .tooltip-content pre {
      background-color: var(--light-gray);
      padding: 8px;
      border-radius: 4px;
      font-family: monospace;
      white-space: pre-wrap;
      margin: 8px 0;
    }

    .tooltip-content p {
      margin: 8px 0;
    }

    .tooltip-title {
      color: var(--primary-color);
      margin-bottom: 20px;
      padding-bottom: 10px;
      border-bottom: 1px solid var(--mid-gray);
    }

    .card-title {
      color: var(--primary-color);
      margin-bottom: 15px;
      padding-bottom: 8px;
      border-bottom: 1px solid var(--mid-gray);
      font-weight: 600;
      display: flex;
      align-items: center;
      gap: 8px;
    }

    .card-icon {
      color: var(--primary-color);
    }

    .result-content {
      padding: 15px;
      background-color: white;
      border-radius: var(--border-radius);
      border: 1px solid var(--mid-gray);
      min-height: 80px;
      font-family: "Inter", "Segoe UI", Tahoma, Geneva, Verdana, sans-serif;
      font-size: 0.95rem;
      line-height: 1.5;
      overflow-x: auto;
    }

    /* Add text highlighting capabilities for result-content */
    .result-content .highlight-error {
      color: var(--danger-color);
      font-weight: 500;
    }

    .result-content .highlight-warning {
      color: var(--warning-color);
      font-weight: 500;
    }

    .result-content .highlight-success {
      color: var(--accent-color);
      font-weight: 500;
    }

    .result-content .highlight-info {
      color: var(--secondary-color);
      font-weight: 500;
    }

    .result-content .highlight-neutral {
      color: var(--secondary-color);
      font-weight: 500;
    }

    /* 代码片段高亮 */
    .code-snippet {
      background-color: #f8fafc;
      border-left: 3px solid var(--primary-color);
    }

    .basic-info-list {
      display: grid;
      grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
      /* 响应式网格布局 */
      gap: 15px;
      padding: 10px 0;
    }

    .basic-info-item {
      display: flex;
      flex-direction: column;
      padding: 8px 10px;
      background-color: white;
      border-radius: var(--border-radius);
      border: 1px solid var(--mid-gray);
    }

    .basic-info-item strong {
      color: var(--secondary-color);
      font-size: 0.85rem;
      margin-bottom: 4px;
    }

    .basic-info-item span {
      word-break: break-all;
      font-size: 0.95rem;
    }

    .table-wrapper {
      overflow-x: auto;
      border-radius: var(--border-radius);
      border: 1px solid var(--mid-gray);
    }

    .files-table {
      width: 100%;
      border-collapse: collapse;
      background-color: white;
      min-width: 600px;
      /* 确保表格在小屏幕可滚动 */
    }

    .files-table th,
    .files-table td {
      padding: 12px 15px;
      text-align: left;
      border-bottom: 1px solid var(--mid-gray);
    }

    .files-table th {
      background-color: var(--light-gray);
      font-weight: 600;
      font-size: 0.9rem;
      color: var(--secondary-color);
      position: relative;
      top: 0;
      z-index: 10;
      cursor: pointer;
      user-select: none;
    }

    .files-table th:hover {
      background-color: #e9ecef;
    }

    .files-table th.sorted {
      background-color: #e0f2fe;
    }

    .sort-indicator {
      margin-left: 8px;
      font-size: 12px;
    }

    .files-table th[data-sort] {
      padding-right: 10px;
      cursor: pointer;
    }

    .files-table tr:hover {
      background-color: rgba(37, 99, 235, 0.03);
    }

    .files-table tr:last-child td {
      border-bottom: none;
    }

    .files-table .issue-type {
      cursor: pointer;
    }

    #data-table tr {
      cursor: pointer;
      height: 50px;
      overflow: hidden;
    }

    #data-table td {
      white-space: nowrap;
      /* 禁止文本换行 */
      overflow: hidden;
      /* 超出部分隐藏 */
      text-overflow: ellipsis;
      /* 显示省略号 */
      vertical-align: middle;
      /* 文本垂直居中 */
      max-width: 0;
      /* 配合ellipsis实现任意宽度下的省略 */
    }

    #data-table th:nth-child(1),
    #data-table td:nth-child(1) {
      width: 70px;
      /* 类型列 */
    }

    #data-table th:nth-child(2),
    #data-table td:nth-child(2) {
      width: 80px;
      /* 规则ID列 */
    }

    #data-table th:nth-child(3),
    #data-table td:nth-child(3) {
      /* max-width: 80px; */
    }

    #data-table th:nth-child(4),
    #data-table td:nth-child(4) {
      width: 160px;
      /* 行范围列 */
    }

    #data-table th:nth-child(5),
    #data-table td:nth-child(5) {
      /* 文件名称列 */
      max-width: 40px;
    }

    .status-merged {
      color: var(--accent-color);
      font-weight: 500;
      display: inline-flex;
      align-items: center;
      gap: 4px;
    }

    .status-merged::before {
      content: "✓";
    }

    .status-open {
      color: var(--primary-color);
      font-weight: 500;
      display: inline-flex;
      align-items: center;
      gap: 4px;
    }

    .status-open::before {
      content: "○";
    }

    .status-abandoned {
      color: var(--danger-color);
      font-weight: 500;
      display: inline-flex;
      align-items: center;
      gap: 4px;
    }

    .status-abandoned::before {
      content: "✕";
    }

    /* 问题等级样式 */
    .level-S {
      color: var(--danger-color);
      font-weight: 500;
    }

    .level-A {
      color: var(--warning-color);
      font-weight: 500;
    }

    .level-BC {
      color: var(--primary-color);
      font-weight: 500;
    }

    /* 抽屉样式 */
    .drawer {
      position: fixed;
      top: 0;
      right: 0;
      width: 420px;
      max-width: 100%;
      /* 移动端全屏 */
      height: 100%;
      background: white;
      box-shadow: -4px 0 20px rgba(0, 0, 0, 0.1);
      z-index: 1000;
      transform: translateX(100%);
      /* 初始隐藏 */
      transition: transform 0.3s ease;
    }

    .drawer.open {
      transform: translateX(0);
      /* 显示时滑入 */
    }

    .drawer-content {
      height: 100%;
      padding: 25px 20px 20px;
      overflow-y: auto;
    }

    .drawer-title {
      color: var(--primary-color);
      margin-bottom: 20px;
      padding-bottom: 10px;
      border-bottom: 1px solid var(--mid-gray);
    }

    .detail-item {
      margin-bottom: 20px;
    }

    .detail-item h4 {
      margin-bottom: 8px;
      color: var(--secondary-color);
      font-size: 0.95rem;
    }

    .close-btn {
      position: absolute;
      top: 15px;
      right: 15px;
      background: none;
      border: none;
      cursor: pointer;
      font-size: 1.2rem;
      color: var(--secondary-color);
      width: 32px;
      height: 32px;
      border-radius: 50%;
      display: flex;
      align-items: center;
      justify-content: center;
      transition: var(--transition-fast);
      z-index: 10;
    }

    .close-btn:hover {
      color: var(--danger-color);
      background-color: var(--light-gray);
    }

    /* 响应式 */
    @media (max-width: 768px) {
      .container {
        padding: 20px 15px;
      }

      .input-group {
        flex-direction: column;
      }

      .basic-info-list {
        grid-template-columns: 1fr;
        /* 移动端单列 */
      }

      .drawer {
        width: 100%;
      }
    }

    /* 动画类 */
    .fade-in {
      animation: fadeIn 0.5s ease forwards;
    }

    @keyframes fadeIn {
      to {
        opacity: 1;
        transform: translateY(0);
      }
    }

    /* 在styles.css中添加选项样式 */
    .analysis-options {
      background-color: var(--light-gray);
      padding: 15px;
      border-radius: var(--border-radius);
      border: 1px solid var(--mid-gray);
    }

    .option-item {
      display: flex;
      align-items: center;
      margin-bottom: 10px;
    }

    .option-item:last-child {
      margin-bottom: 0;
    }

    .option-item input {
      margin-right: 8px;
      width: 16px;
      height: 16px;
    }

    .option-item label {
      cursor: pointer;
      color: var(--dark-gray);
      font-size: 0.95rem;
    }

    .btn-excelBtn {
      padding: 10px 20px;
      background-color: var(--primary-color);
      color: white;
      border: none;
      border-radius: var(--border-radius);
      cursor: pointer;
      font-size: 12px;
      font-weight: 500;
      transition: var(--transition);
      white-space: nowrap;
      position: absolute;
      right: 2%;
    }

    .btn-excelBtn:hover {
      background-color: var(--primary-light);
      transform: translateY(-1px);
    }

    /* 弹窗动画样式 */
    #approvalPopup>div {
      transform: scale(0.95);
      transition: transform 0.2s ease-out;
    }

    #approvalPopup>div.scale-100 {
      transform: scale(1);
    }

    /* 分页按钮基础样式 */
    .page-btn {
      padding: 4px 12px;
      border: 1px solid #d1d5db;
      border-radius: 6px;
      color: white;
      background-color: var(--primary-light);
      cursor: pointer;
      font-size: 14px;
      margin: 0 2px;
    }

    /* 悬停效果 */
    .page-btn:hover {
      background-color: var(--primary-color);
    }

    /* 禁用状态 */
    .page-btn.disabled {
      opacity: 0.5;
      cursor: not-allowed;
      pointer-events: none;
      /* 阻止点击事件 */
    }

    /* 当前页样式 */
    .page-btn.current {
      background-color: #3b82f6;
      color: white;
      border-color: #3b82f6;
    }

    /* 中间页码按钮基础样式 */
    .medium-page-btn {
      padding: 4px 12px;
      border: 1px solid #d1d5db;
      border-radius: 6px;
      color: black;
      background-color: white;
      cursor: pointer;
      font-size: 14px;
      margin: 0 2px;
    }

    /* 悬停效果 */
    .medium-page-btn:hover {
      background-color: var(--primary-color);
    }

    /* 禁用状态 */
    .medium-page-btn.disabled {
      opacity: 0.5;
      cursor: not-allowed;
      pointer-events: none;
      /* 阻止点击事件 */
    }

    /* 当前页样式 */
    .medium-page-btn.current {
      background-color: #6195e9;
      color: white;
      border-color: #3b82f6;
    }


    /* 分页容器 */
    .pagination {
      display: flex;
      align-items: center;
      gap: 5px;
      margin: 20px 0;
    }

    .table-filters {
      padding: 15px;
      background-color: var(--light-gray);
      border-bottom: 1px solid #ddd;
    }

    .search-box {
      padding: 8px 12px;
      width: 300px;
      border: 1px solid #ddd;
      border-radius: 4px;
      font-size: 14px;
    }

    .filter-group {
      display: inline-block;
      margin-left: 15px;
    }

    .filter-select {
      padding: 8px 12px;
      border: 1px solid #ddd;
      border-radius: 4px;
      font-size: 14px;
    }

    .pagination {
      display: flex;
      justify-content: center;
      align-items: center;
      padding: 15px;
      background-color: var(--light-gray);
      border-top: 1px solid #ddd;
    }

    /* 过渡动画基础样式 */
    .transition-opacity {
      transition-property: opacity;
      transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
    }

    .duration-300 {
      transition-duration: 300ms;
    }

    .opacity-0 {
      opacity: 0;
    }

    #centerText {
      position: absolute;
      top: 0;
      left: 0;
      text-align: center;
      white-space: nowrap;
      background: transparent;
      pointer-events: none;
      /* 防止中心文本干扰鼠标事件 */
      z-index: 100;
      /* 确保在饼图上方显示 */
    }

    #issuesDistributionContainer {
      position: relative;
    }

    #issuesDistributionChartPie {
      z-index: 1;
    }
  </style>
</head>

<body>
  <div class="container">
    <header>
      <div class="header-content">
        <i class="fas fa-code-branch header-icon"></i>
        <h1>Gerrit链接解析工具解析报告-{{changeID}}</h1>
      </div>
      <p class="timestamp">生成时间: {{ generated_time }}</p>
    </header>

    <section class="result-section" id="resultContainer">
      <!-- 基础信息 -->
      <div id="basicInfoContainer" class="details-card" style="opacity: 0; transform: translateY(10px)">
        <h3 class="card-title">
          <i class="fas fa-info-circle card-icon"></i>基础信息
        </h3>
        <div class="basic-info-list">
          <div class="basic-info-item">
            <strong>编号:</strong>
            <span id="basicNumber"></span>
          </div>
          <div class="basic-info-item">
            <strong>分支:</strong>
            <span id="basicBranch"></span>
          </div>
          <div class="basic-info-item">
            <strong>Change ID:</strong>
            <span id="basicChangeId"></span>
          </div>
          <div class="basic-info-item">
            <strong>创建时间:</strong>
            <span id="basicCreated"></span>
          </div>
          <div class="basic-info-item">
            <strong>状态:</strong>
            <span id="basicStatus"></span>
          </div>
          <div class="basic-info-item">
            <strong>标题:</strong>
            <span id="basicSubject"></span>
          </div>
          <div class="basic-info-item">
            <strong>提交者:</strong>
            <span id="basicSubmitter"></span>
          </div>
        </div>
      </div>
      <!-- 文件变动信息 -->
      <div id="filesTableContainer" class="details-card" style="display: none; opacity: 0; transform: translateY(10px)">
        <h3 class="card-title">
          <i class="fas fa-file-code card-icon"></i>文件变动信息
        </h3>
        <div class="table-wrapper">
          <table class="files-table">
            <thead>
              <tr>
                <th>文件路径</th>
                <th>插入行数</th>
                <th>删除行数</th>
              </tr>
            </thead>
            <tbody id="filesTableBody"></tbody>
          </table>
        </div>
      </div>

      <!-- 工作流返回信息 -->
      <div id="workflowContainer" class="details-card" style="display: none; opacity: 0; transform: translateY(10px)">
        <h3 class="card-title">
          <i class="fas fa-check-circle card-icon"></i>代码审核结果
        </h3>
        <pre id="workflowResults" class="result-content">
                    <span class="highlight-info"></span>
                    <span class="highlight-warning"></span>
                </pre>
        <div class="flex justify-between items-center mb-6">
          <h4 class="text-lg" style="font-size: 20px; margin-top: 10px">
            问题列表
          </h4>
          <button id="exportExcelBtn"
            class="btn-excelBtn flex items-center gap-2 bg-blue-600 hover:bg-blue-700 text-white px-4 py-2 rounded-md transition-colors duration-200 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2">
            <i class="fa fa-download"></i>
            <span>导出Excel</span>
          </button>
        </div>
        <div id="issuesList" style="margin-top: 40px; display: none">
          <div class="table-wrapper" id="issuesTable">
            <div class="table-filters flex justify-between items-center">
              <input type="text" class="search-box" placeholder="搜索任何内容..." />

              <div class="filter-group">
                <select class="filter-select rank-filter">
                  <option value="">所有等级</option>
                  <option value="S级">S级</option>
                  <option value="A级">A级</option>
                  <option value="B级">B级</option>
                  <option value="C级">C级</option>
                </select>
              </div>

              <div class="filter-group">
                <select class="filter-select file-filter">
                  <option value="">所有文件</option>
                </select>
              </div>
            </div>
            <table class="files-table" id="data-table">
              <thead>
                <tr>
                  <th data-sort="type">
                    类型
                    <i class="fas sort-indicator"></i>
                  </th>
                  <th data-sort="description">
                    规则ID
                    <i class="fas sort-indicator"></i>
                  </th>
                  <th>描述</th>
                  <th>行范围</th>
                  <th data-sort="filename">
                    文件名称
                    <i class="fas sort-indicator"></i>
                  </th>
                </tr>
              </thead>
              <tbody id="analyseTableBody"></tbody>
            </table>
          </div>
          <div class="mt-4 flex justify-between items-center" id="paginationContainer">
            <div class="text-sm text-neutral-500">
              显示 <span id="pageRange">1-4</span> 条，共
              <span id="totalItems">0</span> 条
            </div>
            <div class="pagination" id="paginationControls">
              <button id="prevBtn" class="page-btn">
                <i class="fas fa-chevron-left"></i> 上一页
              </button>
              <div id="page-numbers">
                <!-- 页码按钮将通过JavaScript动态生成 -->
              </div>
              <button id="nextBtn" class="page-btn">
                下一页 <i class="fas fa-chevron-right"></i>
              </button>
            </div>
          </div>
        </div>
      </div>

      <!-- 问题详情显示抽屉 -->
      <div id="drawerContainer" class="drawer">
        <button id="closeDrawerBtn" class="close-btn" aria-label="关闭抽屉">
          <i class="fas fa-times"></i>
        </button>
        <div class="drawer-content">
          <h3 class="drawer-title">问题详情</h3>
          <div class="detail-item">
            <h4>文件</h4>
            <p id="filenameDisplay" class="result-content"></p>
          </div>
          <div class="detail-item">
            <h4>类型</h4>
            <p id="typeDisplay" class="result-content"></p>
          </div>
          <div class="detail-item">
            <h4>规则ID</h4>
            <p id="idDisplay" class="result-content"></p>
          </div>
          <div class="detail-item">
            <h4>描述</h4>
            <p id="descDisplay" class="result-content"></p>
          </div>
          <div class="detail-item">
            <h4>行范围</h4>
            <pre id="rangeDisplay" class="result-content"></pre>
          </div>
          <div class="detail-item">
            <h4>代码片段</h4>
            <pre id="snippetPreview" class="result-content code-snippet"></pre>
          </div>
          <div class="detail-item">
            <h4>建议</h4>
            <p id="suggestTip" class="result-content"></p>
          </div>
        </div>
      </div>

      <div id="issuesDistributionContainer" class="details-card"
        style="display: none; opacity: 0; transform: translateY(10px)">
        <h3 class="card-title">
          <i class="fas fa-chart-pie card-icon"></i>问题分布图
        </h3>
        <div class="flex items-center justify-between gap-4" style="width: 100%; padding: 10px; border: 1px solid #eee">
          <div class="flex h-64" style="position: relative">
            <canvas id="issuesDistributionChartPie"></canvas>
            <div id="centerText" style="
                  position: absolute;
                  top: 50%;
                  left: 39.5%;
                  transform: translate(-50%, -50%);
                  text-align: center;
                "></div>
          </div>
        </div>
      </div>
      <!-- 详情浮窗 -->
      <div id="detailTooltip"
        class="tooltip-shadow bg-white rounded-lg p-5 absolute z-50 transition-all duration-200 opacity-0 transform translate-y-2">
        <div class="tooltip-content">
          <h3 class="tooltip-title">问题详情</h3>
          <div class="detail-item">
            <h4>描述</h4>
            <p id="tooltip-suggestTip" class="result-content"></p>
          </div>
          <div class="detail-item">
            <h4>代码片段</h4>
            <pre id="tooltip-snippetPreview" class="result-content code-snippet"></pre>
          </div>
        </div>
      </div>
  </div>
  <script>
    // 常量定义
    const DOM_SELECTORS = {
      closeDrawerBtn: "#closeDrawerBtn",
      // 基本信息元素
      basicInfoContainer: "#basicInfoContainer",
      basicNumber: "#basicNumber",
      basicBranch: "#basicBranch",
      basicChangeId: "#basicChangeId",
      basicCreated: "#basicCreated",
      basicStatus: "#basicStatus",
      basicSubject: "#basicSubject",
      basicSubmitter: "#basicSubmitter",
      // 文件变动元素
      filesTableContainer: "#filesTableContainer",
      filesTableBody: "#filesTableBody",
      // 检测结果元素
      workflowContainer: "#workflowContainer",
      workflowResults: "#workflowResults",
      issuesList: "#issuesList",
      issuesTable: "#issuesTable",
      analyseTableBody: "#analyseTableBody",
      prevBtn: "#prevBtn",
      nextBtn: "#nextBtn",
      pageNumbersContainer: "#page-numbers",
      searchBox: ".search-box",
      rankFilter: ".rank-filter",
      fileFilter: ".file-filter",
      datatable: "#data-table",
      //导出按钮
      exportExcelBtn: "#exportExcelBtn",
      // 抽屉元素
      drawerContainer: "#drawerContainer",
      snippetPreview: "#snippetPreview",
      suggestTip: "#suggestTip",
      typeDisplay: "#typeDisplay",
      idDisplay: "#idDisplay",
      descDisplay: "#descDisplay",
      rangeDisplay: "#rangeDisplay",
      filenameDisplay: "#filenameDisplay",
      //浮窗元素
      tooltip: "#detailTooltip",
      tooltipContent: ".tooltip-content",
      tooltipsnippetPreview: "#tooltip-snippetPreview",
      tooltipsuggestTip: "#tooltip-suggestTip",
      //饼状图元素
      issuesDistributionContainer: "#issuesDistributionContainer",
      issuesDistributionChartPie: "#issuesDistributionChartPie",
      centerText: "#centerText",
    };
    // 时间提取正则
    const TIME_PATTERN = /\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}/;
    // 全局元素对象
    let elements = {};
    let issue_details_datas = [];
    let issuesDistributionInstancePie = null;
    // 状态样式映射
    const STATUS_CLASSES = {
      MERGED: "status-merged",
      OPEN: "status-open",
      ABANDONED: "status-abandoned",
      NEW: "status-open",
    };
    //问题等级样式映射
    const TYPE_CLASSES = {
      S级: "level-S",
      A级: "level-A",
      B级: "level-BC",
      C级: "level-BC",
    };
    // 饼状图中心文本样式映射
    const CENTERTEXT_CLASSES = {
      S级: "ef4444",
      A级: "f59e0b",
      "B/C级": "2563eb",
    };
    let critical_issues = [];
    let high_risk_issues = [];
    let code_quality_issues = [];
    let unique_filenames = new Set();
    let same_ruleid_counts_map = new Map();
    //分页信息
    let currentPage = 1;
    let itemsPerPage = 6;
    let totalItems = 0;
    let totalPages = 1;
    let filteredData = [];
    let sortField = "type";
    let sortDirection = "asc";
    let timer = null;
    let isleaveTooltip = true;
    let currentmouseRow = null;
    let hoverTimer = null;
    let is_drawerOpen = false;

    // 工具函数
    function loadDOMElements() {
      elements = Object.entries(DOM_SELECTORS).reduce(
        (acc, [key, selector]) => {
          const el = document.querySelector(selector);
          if (!el) {
            console.error(`缺失元素: ${selector}`);
            return acc;
          }
          return { ...acc, [key]: el };
        },
        {}
      );
    }

    // 设置按钮状态
    function setButtonState(button, disabled, text) {
      button.disabled = disabled;
      // 先检查元素是否存在
      const btnText = button.querySelector(".btn-text");
      const spinner = button.querySelector(".loading-spinner");

      // 只有在元素存在的情况下才操作
      if (btnText && text !== undefined) {
        btnText.textContent = text;
      }

      if (btnText && spinner) {
        if (disabled) {
          spinner.style.display = "inline-block";
          btnText.style.display = "none";
        } else {
          spinner.style.display = "none";
          btnText.style.display = "inline-block";
        }
      }
    }

    function showWithAnimation(element) {
      element.style.display = "block";
      // 触发重排后添加动画类
      setTimeout(() => {
        element.classList.add("fade-in");
      }, 10);
    }

    // 清除之前的结果
    function clearPreviousResults() {
      //清空问题内容
      issue_details_datas = [];
      critical_issues = [];
      high_risk_issues = [];
      code_quality_issues = [];
      //分页信息
      currentPage = 1;
      itemsPerPage = 6;
      totalItems = 0;
      totalPages = 1;
      filteredData = [];
      sortField = "type";
      sortDirection = "asc";
      elements.rankFilter.value = "";
      elements.fileFilter.value = "";

      elements.connectionResult.textContent = "";
      //清空基础信息区域
      elements.basicNumber.textContent = "";
      elements.basicBranch.textContent = "";
      elements.basicChangeId.textContent = "";
      elements.basicCreated.textContent = "";
      elements.basicStatus.textContent = "";
      elements.basicSubject.textContent = "";
      elements.basicSubmitter.textContent = "";
      // 隐藏基础信息区域
      elements.basicInfoContainer.style.display = "none";
      // 清空文件变动区域
      elements.filesTableBody.innerHTML = "";
      // 隐藏文件变动区域
      elements.filesTableContainer.style.display = "none";
      // 清空工作流分析结果区域
      elements.workflowResults.textContent = "";
      // 清空工作流区域
      elements.filesTableBody.innerHTML = "";
      elements.analyseTableBody.innerHTML = "";
      // 清空浮窗内容
      elements.tooltipsnippetPreview.textContent = "";
      elements.tooltipsuggestTip.textContent = "";
      // 隐藏工作流区域
      elements.workflowContainer.style.display = "none";
      elements.issuesDistributionContainer.style.display = "none";
      // 清空抽屉内容
      elements.snippetPreview.innerHTML = "";
      elements.suggestTip.innerHTML = "";
      elements.typeDisplay.textContent = "";
      elements.idDisplay.textContent = "";
      elements.descDisplay.textContent = "";
      elements.rangeDisplay.textContent = "";
      elements.filenameDisplay.textContent = "";
      elements.issuesDistributionContainer.style.display = "none";
      // 关闭抽屉
      closeDrawer();
      // 重置动画状态
      [
        elements.basicInfoContainer,
        elements.filesTableContainer,
        elements.workflowContainer,
        elements.issuesDistributionContainer,
      ].forEach((el) => {
        el.classList.remove("fade-in");
        el.style.opacity = "0";
        el.style.transform = "translateY(10px)";
      });
    }

    // 更新清空按钮显示状态
    function updateClearButtonVisibility() {
      const hasContent = elements.urlInput.value.trim() !== "";
      if (hasContent) {
        elements.clearBtn.classList.add("visible");
      } else {
        elements.clearBtn.classList.remove("visible");
      }
    }

    // 清空输入框内容
    function clearInput() {
      elements.urlInput.value = "";
      updateClearButtonVisibility();
      elements.urlInput.focus();
    }
    // 关闭抽屉
    function closeDrawer() {
      elements.drawerContainer.classList.remove("open");
      // 动画结束后隐藏
      setTimeout(() => {
        elements.drawerContainer.style.display = "none";
      }, 300);
      is_drawerOpen = false;
    }

    // 添加 HTML 转义函数
    function escapeHtml(unsafe) {
      if (!unsafe) return '';
      return unsafe
        .replace(/&/g, "&amp;")
        .replace(/</g, "&lt;")
        .replace(/>/g, "&gt;")
        .replace(/"/g, "&quot;")
        .replace(/'/g, "&#039;");
    }
    function appendIssueRow(issue, parent) {
      const row = document.createElement("tr");
      row.innerHTML = `
      <td class="issue-type ${TYPE_CLASSES[issue.type]}">${issue.type}</td>
      <td class="rule-id">${issue.rule_id}</td>
      <td>${escapeHtml(issue.description)}</td>
      <td><b>[${issue.line_range}]</b></td>
      <td>${issue.filename}</td>
      `;
      parent.appendChild(row);
    }

    // 显示抽屉函数
    function showDrawer(issue) {
      elements.drawerContainer.style.display = "block";
      // 延迟添加open类触发动画
      setTimeout(() => {
        elements.drawerContainer.classList.add("open");
      }, 10);
      // 填充内容
      elements.snippetPreview.innerHTML = escapeHtml(issue.code_snippet);
      elements.suggestTip.innerHTML = escapeHtml(issue.advice);
      elements.typeDisplay.textContent = issue.type;
      elements.idDisplay.textContent = issue.rule_id;
      elements.descDisplay.textContent = issue.description;
      elements.rangeDisplay.textContent = `[${issue.line_range}]`;
      elements.filenameDisplay.textContent = issue.filename;
    }

    // 动态渲染问题表格
    function renderIssueList(issues) {
      elements.issuesList.style.display = "block";
      issues_number =
        issues["critical_issues"].length +
        issues["high_risk_issues"].length +
        issues["code_quality_issues"].length;
      let question_info = "总问题个数：" +
        issues_number +
        "个\nS级问题个数：" +
        issues["critical_issues"].length +
        "个\nA级问题个数：" +
        issues["high_risk_issues"].length +
        "个\nB级问题个数：" +
        issues["code_quality_issues"].length +
        "个";
      initchart(
        issues["critical_issues"].length,
        issues["high_risk_issues"].length,
        issues["code_quality_issues"].length,
        issues_number
      );
      critical_issues = issues["critical_issues"];
      high_risk_issues = issues["high_risk_issues"];
      code_quality_issues = issues["code_quality_issues"];
      // 填充文件变动信息表格
      if (issues_number === 0) {
        const emptyRow = document.createElement("tr");
        emptyRow.innerHTML =
          '<td colspan="6" style="text-align: center; padding: 20px;">该代码没有异常问题</td>';
        elements.analyseTableBody.appendChild(emptyRow);
      } else {
        issues["critical_issues"].forEach((issue) => {
          const currentCount = same_ruleid_counts_map.get(issue.rule_id) || 0;
          if (currentCount < 10) {
            issue_details_datas.push(issue);
            unique_filenames.add(issue.filename);
          }
          same_ruleid_counts_map.set(issue.rule_id, currentCount + 1);
        });
        issues["high_risk_issues"].forEach((issue) => {
          const currentCount = same_ruleid_counts_map.get(issue.rule_id) || 0;
          if (currentCount < 10) {
            issue_details_datas.push(issue);
            unique_filenames.add(issue.filename);
          }
          same_ruleid_counts_map.set(issue.rule_id, currentCount + 1);
        });
        issues["code_quality_issues"].forEach((issue) => {
          const currentCount = same_ruleid_counts_map.get(issue.rule_id) || 0;
          if (currentCount < 10) {
            issue_details_datas.push(issue);
            unique_filenames.add(issue.filename);
          }
          same_ruleid_counts_map.set(issue.rule_id, currentCount + 1);
        });
        let rule_id_more_than_ten = [];
        same_ruleid_counts_map.forEach((count, rule_id) => {
          if (count >= 10) {
            rule_id_more_than_ten.push(rule_id);
          }
        });
        if (rule_id_more_than_ten.length > 0) {
          let same_ruleid_descriptions = "\n警告：\n\t其中规则";
          rule_id_more_than_ten.forEach((rule_id, index) => {
            same_ruleid_descriptions += `${rule_id}`;
            if (index < rule_id_more_than_ten.length - 1) {
              same_ruleid_descriptions += `, `;
            }
          });
          same_ruleid_descriptions +=
            " 有不小于10个同类型问题,  当前同类型问题均最多只显示10个,  请您仔细检查代码问题并重新提交 ！！！";
          setWorkflowResults([
            { type: 'info', text: question_info },
            { type: 'warning', text: same_ruleid_descriptions }
          ]);
        } else {
          setWorkflowResults([
            { type: 'info', text: question_info }
          ]);
        }
        // 动态添加下拉选项
        const select = document.querySelector(".file-filter");
        unique_filenames.forEach((filename) => {
          select.add(new Option(filename, filename));
        });

        totalItems = issue_details_datas.length;
        totalPages = Math.ceil(totalItems / itemsPerPage);
        currentPage = 1;
        renderissueTable(currentPage, issue_details_datas);
        filteredData = [...issue_details_datas];

        elements.prevBtn.addEventListener("click", () => {
          if (currentPage > 1) {
            currentPage--;
            renderissueTable(currentPage, filteredData);
          }
        });

        elements.nextBtn.addEventListener("click", () => {
          if (currentPage < totalPages) {
            currentPage++;
            renderissueTable(currentPage, filteredData);
          }
        });
      }
      tootipEvent();


      // 搜索框事件
      elements.searchBox.addEventListener("input", filterData);

      // 下拉筛选事件
      elements.rankFilter.addEventListener("change", filterData);
      elements.fileFilter.addEventListener("change", filterData);

      const tableHeaders = elements.datatable.querySelectorAll("th");
      tableHeaders.forEach((header) => {
        if (header.hasAttribute("data-sort")) {
          header.addEventListener("click", () => {
            headerclickEvent(header);
          });
        }
      });
    }

    function tootipEvent() {
      elements.datatable.addEventListener("click", (e) => {
        showdetails_Drawer(e);
        is_drawerOpen = true;
        elements.tooltip.classList.remove("show");
        currentmouseRow = null;
      });
      elements.datatable.addEventListener("mousemove", (e) => {
        // 判断鼠标是否进入了td元素
        if (e.target.tagName === "TD") {
          const newRow = e.target.closest("tr");
          if (newRow && newRow !== currentmouseRow) {
            // 只有当抽屉未打开时才显示tooltip
            if (!is_drawerOpen) {
              showdetails_Tooltip(e);
              currentmouseRow = newRow;
            }
          }
        }
      });
      elements.datatable.addEventListener("mouseout", (e) => {
        const currentTargetRow = e.target.closest("tr");
        if (currentTargetRow && currentTargetRow === currentmouseRow) {
          // 判断鼠标是否移动到了同一行的其他元素（比如同一行的其他td）
          const isMovingWithinRow =
            e.relatedTarget?.closest("tr") === currentmouseRow;
          if (!isMovingWithinRow) {
            clearTimeout(timer);
            if (!isMouseInTooltip()) {
              setTimeout(() => {
                if (!isMouseInTooltip()) {
                  elements.tooltip.classList.remove("show");
                }
              }, 300);
            }
            currentmouseRow = null; // 重置当前行
          }
        }
      });
    }

    function isMouseInTooltip() {
      return elements.tooltip.matches(":hover");
    }
    function headerclickEvent(header) {
      // 如果点击的是当前排序的字段，则切换排序方向
      if (header.dataset.sort === sortField) {
        sortDirection = sortDirection === "asc" ? "desc" : "asc";
      } else {
        // 否则，设置新的排序字段，默认升序
        sortField = header.dataset.sort;
        sortDirection = "asc";
      }
      currentPage = 1;
      renderissueTable(currentPage, filteredData);
    }

    function showdetails_Drawer(e) {
      // 只给td添加点击事件（表格内容行）
      if (e.target.tagName === "TD") {
        const row = e.target.closest("tr");
        const rows = Array.from(elements.datatable.querySelectorAll("tr"));
        const rowIndex = rows.indexOf(row);
        const issue = filteredData[(currentPage - 1) * itemsPerPage + rowIndex - 1];
        showDrawer(issue);
      }
    }

    function showdetails_Tooltip(e) {
      // 只给td添加鼠标响应事件（表格内容行）
      timer = setTimeout(() => {
        const row = e.target.closest("tr");
        const rows = Array.from(elements.datatable.querySelectorAll("tr"));
        const rowIndex = rows.indexOf(row);
        const issue = filteredData[(currentPage - 1) * itemsPerPage + rowIndex - 1];
        elements.tooltipsnippetPreview.innerHTML = escapeHtml(issue.code_snippet);
        elements.tooltipsuggestTip.innerHTML = escapeHtml(issue.description);
        adjustFloatWindowNearMouse(e);
        showTooltip();
      }, 1000);
    }

    function showdetails(e) {
      // 只给td添加点击事件（表格内容行）
      if (e.target.tagName === "TD") {
        const row = e.target.closest("tr");
        const rows = Array.from(elements.datatable.querySelectorAll("tr"));
        const rowIndex = rows.indexOf(row);
        const issue =
          filteredData[(currentPage - 1) * itemsPerPage + rowIndex - 1];
        elements.tooltipsnippetPreview.innerHTML = issue.code_snippet;
        elements.tooltipsuggestTip.innerHTML = issue.advice;
        adjustFloatWindowNearMouse(e);
        showTooltip();
      }
    }

    // 显示浮窗时确保过渡生效
    function showTooltip() {
      const tooltip = elements.tooltip;
      tooltip.style.display = "block"; // 先显示
      setTimeout(() => {
        if (!is_drawerOpen) {
          tooltip.classList.add("show"); // 再触发过渡
        }
      }, 10);
    }

    // 定位浮窗函数 - 确保浮窗不会超出视口
    function positionTooltip(e) {
      const tooltipWidth = elements.tooltip.offsetWidth;
      const tooltipHeight = elements.tooltip.offsetHeight;
      const windowWidth = window.innerWidth;
      const windowHeight = window.innerHeight;

      // 鼠标位置
      let x = e.clientX;
      let y = e.clientY;

      // 计算浮窗位置（鼠标右下方）
      let left = x + 10;
      let top = y + 10;

      // 检查右侧边界
      if (left + tooltipWidth > windowWidth) {
        left = x - tooltipWidth - 15;
      }

      // 检查底部边界
      if (top + tooltipHeight > windowHeight) {
        top = y - tooltipHeight - 15;
      }

      // 应用位置（考虑滚动偏移）
      elements.tooltip.style.left = `${left + window.scrollX}px`;
      elements.tooltip.style.top = `${top + window.scrollY}px`;
    }
    // 调整浮窗尺寸并定位在鼠标附近
    function adjustFloatWindowNearMouse(e) {
      // 1. 先基于鼠标坐标设置初始位置（贴近鼠标）
      const mouseX = e.clientX; // 鼠标水平坐标（视口内）
      const mouseY = e.clientY; // 鼠标垂直坐标（视口内）
      const offset = 10; // 鼠标与浮窗的间距（避免遮挡鼠标）

      // 初始位置：鼠标右下方偏移offset像素
      elements.tooltip.style.left = `${mouseX + offset}px`;
      elements.tooltip.style.top = `${mouseY + offset}px`;

      // 2. 让浮窗自适应内容（移除固定宽高）
      elements.tooltip.style.width = 'auto';
      elements.tooltip.style.height = 'auto';

      // 3. 获取视口和浮窗的尺寸
      const viewportWidth = window.innerWidth;
      const viewportHeight = window.innerHeight;
      const contentWidth = elements.tooltip.offsetWidth;
      const contentHeight = elements.tooltip.offsetHeight;

      // 4. 限制浮窗最大尺寸（不超过视口的80%）
      const maxWidth = viewportWidth * 0.8;
      const maxHeight = viewportHeight * 0.8;
      const finalWidth = Math.min(contentWidth, maxWidth);
      const finalHeight = Math.min(contentHeight, maxHeight);

      // 应用计算后的尺寸
      elements.tooltip.style.width = `${finalWidth}px`;
      elements.tooltip.style.height = `${finalHeight}px`;

      // 5. 修正位置：确保浮窗在视口内，且尽量贴近鼠标
      const floatWidth = finalWidth;
      const floatHeight = finalHeight;

      // 计算基于鼠标的理想位置（可能超出视口）
      let idealLeft = mouseX + offset;
      let idealTop = mouseY + offset;

      // 边界调整：右侧超出则左移到鼠标左侧
      if (idealLeft + floatWidth > viewportWidth) {
        idealLeft = mouseX - floatWidth - offset;
      }

      // 边界调整：底部超出则上移到鼠标上方
      if (idealTop + floatHeight > viewportHeight) {
        idealTop = mouseY - floatHeight - offset;
      }

      // 最终限制：确保不超出视口边缘（极端情况）
      const constrainedLeft = Math.max(0, Math.min(idealLeft, viewportWidth - floatWidth));
      const constrainedTop = Math.max(0, Math.min(idealTop, viewportHeight - floatHeight));

      // 应用最终位置
      elements.tooltip.style.left = `${constrainedLeft}px`;
      elements.tooltip.style.top = `${constrainedTop}px`;
    }

    function initdata() {
      // const detailData = {{ detail_data_json|safe }};
      const detailData = {{ detail_data| tojson
    }};
    const basicInfo = detailData.basicInfo;
    const accountInfo = detailData.accountInfo;
    const changedFiles = detailData.changedFiles;
    const analysisResult = detailData.analysisResult;
    // 显示基础信息结果容器
    showWithAnimation(elements.basicInfoContainer);
    // 填充基础信息
    elements.basicNumber.textContent = basicInfo._number || "未知";
    elements.basicBranch.textContent = basicInfo.branch || "未知";
    elements.basicChangeId.textContent = basicInfo.change_id || "未知";
    elements.basicCreated.textContent =
      basicInfo.created.match(TIME_PATTERN)[0] || "未知";
    elements.basicStatus.textContent = basicInfo.status || "未知";
    elements.basicStatus.className = STATUS_CLASSES[basicInfo.status] || "";
    elements.basicSubject.textContent = basicInfo.subject || "未知";
    elements.basicSubmitter.textContent =
      accountInfo.account_info?.name || "未知";
    //显示文件变动信息容器
    showWithAnimation(elements.filesTableContainer);
    // 填充文件变动信息表格
    if (Object.keys(changedFiles).length === 0) {
      const emptyRow = document.createElement("tr");
      emptyRow.innerHTML =
        '<td colspan="6" style="text-align: center; padding: 20px;">没有文件变动信息</td>';
      elements.filesTableBody.appendChild(emptyRow);
    } else {
      const fragment = document.createDocumentFragment();
      Object.entries(changedFiles)
        .slice(1)
        .forEach(([filePath, fileInfo]) => {
          const row = document.createElement("tr");
          row.innerHTML = `
                  <td>${filePath}</td>
                  <td style="color: green;">${fileInfo.lines_inserted || 0}</td>
                  <td style="color: red;">${fileInfo.lines_deleted || 0}</td>
              `;
          fragment.appendChild(row);
        });
      elements.filesTableBody.appendChild(fragment);
    }
    //填充分析结果
    if (Object.keys(analysisResult).length === 0) {
      return;
    }

    showWithAnimation(elements.workflowContainer);
    showWithAnimation(elements.issuesDistributionContainer);
    renderIssueList(analysisResult);
    }

    function initEventListeners() {
      // 绑定抽屉关闭事件
      elements.closeDrawerBtn.addEventListener("click", closeDrawer);
      elements.exportExcelBtn.addEventListener("click", async () => {
        try {
          await exportExcel();
          // 添加导出成功提示
          showExportSuccessToast();
        } catch (error) {
          alert("导出失败: " + error.message);
        }
      });
      initdata();
      // 添加点击非浮窗区域隐藏浮窗的功能
      document.addEventListener("click", (e) => {
        // 检查点击的元素是否在浮窗内部
        if (elements.tooltip && !elements.tooltip.contains(e.target)) {
          // 如果浮窗正在显示，则隐藏它
          if (elements.tooltip.classList.contains("show")) {
            elements.tooltip.classList.remove("show");
            currentmouseRow = null;
          }
        }
      });
    }
    async function exportExcel() {
      const exportData = issue_details_datas.map((issue) => ({
        问题类型: issue.type,
        规则ID: issue.rule_id,
        描述: issue.description,
        行范围: `[${issue.line_range}]`,
        文件名: issue.filename,
        代码片段: issue.code_snippet,
        建议: issue.advice,
      }));
      const worksheet = XLSX.utils.json_to_sheet(exportData);
      const workbook = XLSX.utils.book_new();
      XLSX.utils.book_append_sheet(workbook, worksheet, "问题列表");
      // 设置列宽
      const wscols = [
        { wch: 10 }, // 问题类型
        { wch: 10 }, // 规则ID
        { wch: 30 }, // 描述
        { wch: 10 }, // 行范围
        { wch: 20 }, // 文件名
        { wch: 40 }, // 代码片段（加宽列宽）
        { wch: 40 }, // 建议（加宽列宽）
      ];
      worksheet["!cols"] = wscols;
      XLSX.writeFile(
        workbook,
        `问题列表_${new Date().toLocaleDateString().replace(/\//g, "-")}.xlsx`
      );
    }

    // 导出成功提示
    function showExportSuccessToast() {
      // 创建提示元素
      const toast = document.createElement("div");
      // 调整z-index值
      toast.className =
        "fixed bottom-4 right-4 bg-green-500 text-white px-4 py-2 rounded-lg shadow-lg flex items-center gap-2 z-500";
      toast.innerHTML = `
          <i class="fa fa-check-circle"></i>
          <span>Excel导出成功！</span>
      `;

      // 添加到页面
      document.body.appendChild(toast);

      // 3秒后自动移除
      setTimeout(() => {
        toast.classList.add(
          "opacity-0",
          "transition-opacity",
          "duration-300"
        );
        setTimeout(() => toast.remove(), 300);
      }, 3000);
    }

    function initchart(s_count, a_count, bc_count, total) {
      elements.issuesDistributionContainer.style.display = "block";
      renderPiechart(s_count, a_count, bc_count, total);
    }
    function positionCenterTextByPercentage(chartInstance) {
      const centerTextEl = elements.centerText;
      const container = chartInstance.canvas.parentElement; // 饼图父容器（定位上下文）

      // 容错：确保容器和图表存在
      if (!centerTextEl || !container || !chartInstance.chartArea) {
        centerTextEl.style.display = "none";
        return;
      }

      // 1. 获取图表区域（chartArea 是 Chart.js 提供的有效绘制区域）
      const { left: chartLeft, top: chartTop, width: chartWidth, height: chartHeight } = chartInstance.chartArea;

      // 2. 计算圆环中心相对于「图表区域」的百分比
      const centerXPercent = ((chartLeft + chartWidth / 2) / chartInstance.canvas.offsetWidth) * 100; // X轴百分比
      const centerYPercent = ((chartTop + chartHeight / 2) / chartInstance.canvas.offsetHeight) * 100; // Y轴百分比

      // 3. 文本自身居中：通过 transform 偏移自身50%（避免计算文本宽高）
      centerTextEl.style.left = `${centerXPercent}%`;
      centerTextEl.style.top = `${centerYPercent}%`;
      centerTextEl.style.transform = "translate(-50%, -50%)"; // 关键：让文本中心对齐百分比坐标
      centerTextEl.style.transformOrigin = "center"; // 确保旋转等变换不影响定位

      // 4. 基础样式确保可见
      centerTextEl.style.position = "absolute";
      centerTextEl.style.display = "block";
      centerTextEl.style.zIndex = 10;
    }
    function renderPiechart(s_count, a_count, bc_count, total) {
      const issuesDistributionCtx =
        elements.issuesDistributionChartPie.getContext("2d");
      if (issuesDistributionInstancePie) {
        issuesDistributionInstancePie.destroy();
        issuesDistributionInstancePie = null;
      }
      issuesDistributionInstancePie = new Chart(issuesDistributionCtx, {
        type: "doughnut",
        data: {
          labels: ["S级", "A级", "B/C级"],
          datasets: [
            {
              data: [s_count, a_count, bc_count],
              backgroundColor: [
                "#ef4444", // 红色
                "#f59e0b", // 橙色
                "#2563eb", // 蓝色
              ],
              borderWidth: 0,
              hoverOffset: 4,
            },
          ],
        },
        options: {
          responsive: true,
          maintainAspectRatio: false,
          cutout: "50%",
          layout: {
            padding: {
              left: 200,
              right: 300, // 右侧内边距，增加此值会增大图表与右侧图例的距离
            },
          },
          plugins: {
            legend: {
              position: "right",
              labels: {
                padding: 20,
                usePointStyle: true,
                pointStyle: "circle",
                generateLabels: function (chart) {
                  const data = chart.data;
                  if (data.labels.length && data.datasets.length) {
                    return data.labels.map(function (label, i) {
                      const value = data.datasets[0].data[i];
                      const percentage = ((value / total) * 100).toFixed(1);
                      const meta = chart.getDatasetMeta(0);
                      const style = meta.controller.getStyle(i);

                      return {
                        text: `${label}: ${value} 项`,
                        fillStyle: style.backgroundColor,
                        strokeStyle: style.borderColor,
                        lineWidth: style.borderWidth,
                        hidden:
                          isNaN(data.datasets[0].data[i]) ||
                          meta.data[i].hidden,
                        index: i,
                        color: `#${CENTERTEXT_CLASSES[label]}`,
                      };
                    });
                  }
                  return [];
                },
                // 图例样式
                font: {
                  size: 15,
                },
              },
            },
            tooltip: {
              backgroundColor: "rgba(255, 255, 255, 0.9)",
              titleColor: "#1F2937",
              bodyColor: "#4B5563",
              borderColor: "#E5E7EB",
              borderWidth: 1,
              padding: 12,
              boxPadding: 6,
              usePointStyle: true,
              callbacks: {
                label: function (context) {
                  updateCenterText(context, total);
                  return `${context.label}: ${context.raw}项`;
                },
              },
            },
          },
          // 鼠标移动事件监听
          onHover: function (event, elements) {
            // 当鼠标移出所有扇区时清空中心文本
            if (elements.length === 0) {
              const centerText = document.getElementById("centerText");
              centerText.innerHTML = ""; // 清空文本
            }
          },
        },
      });
      // 初始化时显示第一个扇区的信息
      if (s_count > 0) {
        const firstContext = {
          raw: s_count,
          label: "S级"
        };
        updateCenterText(firstContext, total);
      } else if (a_count > 0) {
        const firstContext = {
          raw: a_count,
          label: "A级"
        };
        updateCenterText(firstContext, total);
      } else if (bc_count > 0) {
        const firstContext = {
          raw: bc_count,
          label: "B/C级"
        };
        updateCenterText(firstContext, total);
      } else {
        // 无数据时显示提示，避免文本空白
        elements.centerText.innerHTML = '<div style="color:#999;">无数据</div>';
      }

      // 首次定位（确保文本在正确位置）
      setTimeout(() => {
        if (issuesDistributionInstancePie) {
          positionCenterTextByPercentage(issuesDistributionInstancePie);
        }
      }, 100); // 延迟100ms，等待图表渲染完成（避免时机过早）

      // 窗口缩放时重新定位
      window.addEventListener("resize", function () {
        if (issuesDistributionInstancePie) {
          positionCenterTextByPercentage(issuesDistributionInstancePie);
        }
      });
    }

    // 更新中心文本的函数
    function updateCenterText(context, total) {
      const percentage = Math.round((context.raw / total) * 100);
      elements.centerText.innerHTML = `
        <div style="font-size: 24px; font-weight: bold; color:#${CENTERTEXT_CLASSES[context.label]
        }">${percentage}%</div>
        <div style="font-size: 14px; color: #666;">${context.label}</div>
        <div style="font-size: 12px; color: #999; margin-top: 5px;">共 ${context.raw
        } 项</div>
    `;
    }

    function setWorkflowResults(messages) {
      let html = '';
      messages.forEach(msg => {
        html += `<span class="highlight-${msg.type}">${msg.text}</span>\n`;
      });
      elements.workflowResults.innerHTML = html;
    }

    function updateButtonStates() {
      // 上一页按钮状态
      if (totalItems === 0 || currentPage === 1) {
        elements.prevBtn.classList.add("disabled");
      } else {
        elements.prevBtn.classList.remove("disabled");
      }

      // 下一页按钮状态
      if (totalItems === 0 || currentPage === totalPages) {
        elements.nextBtn.classList.add("disabled");
      } else {
        elements.nextBtn.classList.remove("disabled");
      }
    }

    // 渲染当前页表格数据
    function renderissueTable(page, datas) {
      elements.analyseTableBody.innerHTML = "";
      // 处理空数据状态
      if (datas.length === 0) {
        const emptyRow = document.createElement("tr");
        emptyRow.innerHTML =
          '<td colspan="5" style="text-align: center; padding: 20px;">没有匹配的问题数据</td>';
        elements.analyseTableBody.appendChild(emptyRow);
        updateButtonStates();
        updatePaginationInfo();
        return;
      }
      const sortedData = sortData(datas);
      const startIndex = (page - 1) * itemsPerPage;
      const endIndex = Math.min(startIndex + itemsPerPage, totalItems);
      const currentData = sortedData.slice(startIndex, endIndex);
      const fragment = document.createDocumentFragment();
      currentData.forEach((item) => {
        appendIssueRow(item, fragment);
      });
      elements.analyseTableBody.appendChild(fragment);

      updateButtonStates();
      updatePaginationInfo();
      updateSortIndicators();
    }

    // 排序数据
    function sortData(data) {
      if (sortField === "type") {
        const typeOrder = ["S级", "A级", "B级", "C级"];
        const orderMap = new Map(
          typeOrder.map((item, index) => [item, index])
        );

        return data.sort((a, b) => {
          const indexA = orderMap.get(a[sortField]) ?? typeOrder.length;
          const indexB = orderMap.get(b[sortField]) ?? typeOrder.length;

          const comparison = indexA - indexB;
          return sortDirection === "asc" ? comparison : -comparison;
        });
      }
      return data.sort((a, b) => {
        if (a[sortField] < b[sortField]) {
          return sortDirection === "asc" ? -1 : 1;
        }
        if (a[sortField] > b[sortField]) {
          return sortDirection === "asc" ? 1 : -1;
        }
        return 0;
      });
    }

    // 更新排序指示器
    function updateSortIndicators() {
      const tableHeaders = elements.datatable.querySelectorAll("th");
      tableHeaders.forEach((header) => {
        const indicator = header.querySelector(".sort-indicator");
        if (!indicator) {
          return;
        }
        if (header.dataset.sort === sortField) {
          header.classList.add("sorted");
          indicator.className = `fas sort-indicator ${sortDirection === "asc" ? "fa-sort-up" : "fa-sort-down"
            }`;
        } else {
          header.classList.remove("sorted");
          indicator.className = "fas sort-indicator fa-sort";
        }
      });
    }

    // 过滤数据
    function filterData() {
      const searchTerm = elements.searchBox.value.toLowerCase();
      const rank = elements.rankFilter.value;
      const filename = elements.fileFilter.value;

      filteredData = issue_details_datas.filter((issue) => {
        // 搜索词过滤
        const matchesSearch = Object.values(issue).some((value) =>
          String(value).toLowerCase().includes(searchTerm)
        );

        // 等级过滤
        const matchesrank = !rank || issue.type === rank;

        // 文件名过滤
        const matchesFilename = !filename || issue.filename === filename;

        return matchesSearch && matchesrank && matchesFilename;
      });

      totalItems = filteredData.length;
      totalPages = Math.ceil(totalItems / itemsPerPage);
      // 重置到第一页
      currentPage = 1;
      renderissueTable(currentPage, filteredData);
    }

    // 更新分页信息
    function updatePaginationInfo() {
      elements.pageNumbersContainer.innerHTML = "";
      if (totalItems == 0) {
        document.getElementById("pageRange").textContent = `${0}-${0}`;
      } else {
        const start = (currentPage - 1) * itemsPerPage + 1;
        const end = Math.min(currentPage * itemsPerPage, totalItems);
        document.getElementById("pageRange").textContent = `${start}-${end}`;
      }
      document.getElementById("totalItems").textContent = totalItems;
      let startPage = Math.max(1, currentPage - 2);
      let endPage = Math.min(totalPages, startPage + 4);

      // 确保始终显示5个页码（除非总页数少于5）
      if (endPage - startPage < 4 && totalPages > 5) {
        startPage = Math.max(1, endPage - 4);
      }

      // 添加首页按钮（当不是第一页时）
      if (startPage > 1) {
        const firstBtn = createPageButton(1, "首页");
        elements.pageNumbersContainer.appendChild(firstBtn);

        // 添加省略号
        if (startPage > 2) {
          elements.pageNumbersContainer.appendChild(createEllipsis());
        }
      }

      // 添加中间页码
      for (let i = startPage; i <= endPage; i++) {
        const button = document.createElement("button");
        button.className = `medium-page-btn ${i === currentPage ? "current" : ""}`;
        button.textContent = i;
        elements.pageNumbersContainer.appendChild(button);
      }

      // 添加末页按钮（当不是最后一页时）
      if (endPage < totalPages) {
        // 添加省略号
        if (endPage < totalPages - 1) {
          elements.pageNumbersContainer.appendChild(createEllipsis());
        }

        const lastBtn = createPageButton(totalPages, "末页");
        elements.pageNumbersContainer.appendChild(lastBtn);
      }

      bindPageNumberEvents();
    }

    function createPageButton(pageNum, text = null) {
      const button = document.createElement("button");
      button.className = `page-btn ${pageNum === currentPage ? "current" : ""}`;
      button.textContent = text || pageNum;
      button.dataset.page = pageNum;
      return button;
    }

    function createEllipsis() {
      const ellipsis = document.createElement("span");
      ellipsis.className = "page-ellipsis";
      ellipsis.textContent = "...";
      return ellipsis;
    }

    function bindPageNumberEvents() {
      // 先移除所有现有事件监听，避免重复绑定
      const buttons = elements.pageNumbersContainer.querySelectorAll("button");
      buttons.forEach((button) => {
        // 移除所有事件监听器（通过克隆元素实现）
        const newButton = button.cloneNode(true);
        button.parentNode.replaceChild(newButton, button);
      });


      // 重新绑定事件
      elements.pageNumbersContainer
        .querySelectorAll("button")
        .forEach((button) => {
          button.addEventListener("click", () => {
            let pageNum = 0;
            if (button.textContent === "末页") {
              pageNum = totalPages;
            } else if (button.textContent === "首页") {
              pageNum = 1;
            } else {
              pageNum = button.textContent;
            }

            if (parseInt(pageNum) !== currentPage) {
              // 避免重复点击当前页
              currentPage = parseInt(pageNum);
              renderissueTable(currentPage, filteredData);
            }
          });
        });
    }
    // 初始化
    loadDOMElements();
    initEventListeners();
  </script>
</body>
</html>